前言
之前公司專案,前後端分離架構,且設定在不同站台,發生過如下錯誤
然後才接觸到 CORS 這知識
所以也把之前整理的筆記分享出來,因為它與這系列也息息相關 ~
分享主軸
(Cross-Origin Resource Sharing)是一種機制,允許瀏覽器從不同的來源(域名)請求資源,主要是用來保護瀏覽器,而不是用來保護伺服器
總之就是,Server 還是接的到 Request,且也會回傳 Response,但是 Javascript 是收不到任何資訊的,是瀏覽器刻意不讓我們接到,只要 HTTP 的動詞是 GET 或是 POST ,基本上都會發出去/與回來,但瀏覽器刻意不讓我們接到
1. 前後端分離並部署在同一個域名下
比如後端是 ASP .NET CORE WEB API,且前端站台與後端 API 部署在同一個域名下,這種情況下不會有跨域問題
2. 前後端分離並部署在不同域名下
比如前端網站和後端 API 各自擁有獨立的域名(兩個不同的站台,不同 Domain),這種情況下會產生跨來源(跨域)請求,瀏覽器預設會阻擋這些請求
總結 : 若此 OPTIONS 第一次請求成功後,拿到如上圖中幾種 Header 設定後,比如 Max-Age : 600,表示 600 秒內不會再次檢查
1. Access-Control-Allow-Methods
瀏覽器可以接受的 HTTP 方法(動詞),例如 GET、POST、PUT、DELETE 等
範例:Access-Control-Allow-Methods: GET, POST, PUT, DELETE
2. Access-Control-Allow-Headers
瀏覽器可以接受的自定義 header
範例:Access-Control-Allow-Headers: Content-Type, Authorization
3. Access-Control-Max-Age
瀏覽器可以緩存預檢請求的結果的時間(秒數),在這段時間內不會再次發送預檢請求
範例:Access-Control-Max-Age: 1728000(表示 20000 分鐘)
4. Access-Control-Allow-Origin
允許發送請求的來源(域名)
範例:Access-Control-Allow-Origin: https://example.com
1. 在中介軟體中,使用命名原則或預設原則
var builder = WebApplication.CreateBuilder(args);
// 定義 CORS 原則
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseRouting();
// 啟用預設的 CORS 原則
app.UseCors();
app.MapControllers();
...
// 定義預設的 CORS 原則
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
....
app.UseRouting();
// 啟用預設的 CORS 原則
app.UseCors(MyAllowSpecificOrigins);
app.MapControllers();
....
2. 端點路由
// 定義 CORS 原則
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
....
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
});
...
或是直接設定
app.MapControllers().RequireCors(MyAllowSpecificOrigins)
//這句其實與下面這句是一樣意思
endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins);
補充解說
特定路由指定時可以這樣設定 :endpoints.MapGet("/echo", ...):這個端點使用 RequireCors(MyAllowSpecificOrigins) 來應用特定的 CORS 原則
沒特定路由需要設定,就可以使用 : endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins):這會將 MyAllowSpecificOrigins 原則應用到所有控制器
補充 : 使用端點路由時,CORS 中介軟體必須設定為在呼叫 UseRouting 和 UseEndpoints 之間執行
3. 使用 [EnableCors] 屬性
// 定義 CORS 原則
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseRouting();
// 啟用 CORS 中介軟體,必須在 UseRouting 和 UseEndpoints 之間
app.UseCors();
...
[EnableCors("_myAllowSpecificOrigins")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
4. 停用[EnableCors] 屬性 : [DisableCors]
// 這個方法會停用 CORS
[DisableCors]
[HttpGet("disable-cors")]
public IActionResult DisableCors()
{
return Ok("CORS is disabled for this method.");
}
今日結語
今天這重點也是很重要,本篇文章先針對初步介紹,它還可以更詳細設定,學習這知識,大大可以知道整個應用程式與瀏覽器間的行為模式與原理,使自己對於開發上更可以了解,當碰到此錯誤,就可以知道為什麼!不會鬼打牆!
參考文章
中文官方文件
https://learn.microsoft.com/zh-tw/aspnet/core/security/cors?view=aspnetcore-8.0
英文官方文件
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-8.0